package com.mornd.gulimall.product.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.mornd.gulimall.apis.coupon.ICouponClient;
import com.mornd.gulimall.apis.coupon.to.BoundsTo;
import com.mornd.gulimall.apis.search.ISearchClient;
import com.mornd.gulimall.apis.search.to.SkuEsModel;
import com.mornd.gulimall.apis.ware.IWareClient;
import com.mornd.gulimall.apis.ware.to.SkusHasStockTo;
import com.mornd.gulimall.common.core.exception.ServiceException;
import com.mornd.gulimall.common.core.result.AjaxResult;
import com.mornd.gulimall.common.core.result.R;
import com.mornd.gulimall.product.entity.*;
import com.mornd.gulimall.product.entity.vo.spusave.BoundsVo;
import com.mornd.gulimall.product.entity.vo.spusave.SpecVo;
import com.mornd.gulimall.product.entity.vo.spusave.SpuSaveVo;
import com.mornd.gulimall.product.entity.vo.SpuVo;
import com.mornd.gulimall.product.enums.SpuStatus;
import com.mornd.gulimall.product.mapper.SpuInfoMapper;
import com.mornd.gulimall.product.service.*;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

import static com.mornd.gulimall.common.core.utils.BigDecimals.isValid;
import static org.springframework.util.StringUtils.hasText;

/**
 * <p>
 * spu信息 服务实现类
 * </p>
 *
 * @author mornd
 * @since 2023-07-23
 */
@Slf4j
@Service
public class SpuInfoServiceImpl extends ServiceImpl<SpuInfoMapper, SpuInfo> implements ISpuInfoService {
    @Resource
    private ISpuInfoDescService spuInfoDescService;
    @Resource
    private ISpuImagesService spuImagesService;
    @Resource
    private IProductAttrValueService productAttrValueService;
    @Resource
    private ISkuInfoService skuInfoService;
    @Resource
    private ICouponClient couponClient;
    @Resource
    private ICategoryService categoryService;
    @Resource
    private IBrandService brandService;
    @Resource
    private IAttrService attrService;
    @Resource
    private IWareClient wareClient;
    @Resource
    private ISearchClient searchClient;

    /**
     * 发布商品
     *
     * @param spuSaveVo
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public String saveSpu(SpuSaveVo spuSaveVo) {
        // 1、保存基本信息
        SpuInfo spu = new SpuInfo();
        BeanUtils.copyProperties(spuSaveVo, spu);
        // 默认下架状态
        spu.setPublishStatus(SpuStatus.CREATE.ordinal());
        spu.setCreateTime(LocalDateTime.now());
        super.save(spu);

        // todo 保存积分信息

        // 2、保存商品图集
        if (CollUtil.isNotEmpty(spuSaveVo.getImgs())) {
            spuImagesService.saveImages(spu.getId(), spuSaveVo.getImgs());
        }

        // 3、保存商品介绍图集
        if (CollUtil.isNotEmpty(spuSaveVo.getDescImgs())) {
            spuInfoDescService.saveSpuDescImgs(spu.getId(), spuSaveVo.getDescImgs());
        }

        // 4、保存规格参数
        productAttrValueService.saveSpecs(spu.getId(), spuSaveVo.getSpecs());

        // 5、保存sku
        skuInfoService.saveSkus(spu, spuSaveVo.getSkus());

        // 5、保存积分信息
        BoundsVo bounds = spuSaveVo.getBounds();
        if (bounds != null && (isValid(bounds.getBuyBounds()) || isValid(bounds.getGrowBounds()))) {
            BoundsTo boundsTo = new BoundsTo();
            BeanUtils.copyProperties(spuSaveVo.getBounds(), boundsTo);
            boundsTo.setSpuId(spu.getId());
            try {
                AjaxResult boundsResult = couponClient.saveBounds(boundsTo);
                boolean success = boundsResult.isSuccess();
            } catch (Exception e) {
                // 远程服务不可用，抛出 feign.FeignException$ServiceUnavailable: [503] during [PUT] to [http://service-coupon/coupon/spuBounds] [ICouponClient#saveBounds(BoundsTo)]: [Load balancer does not contain an instance for the service service-coupon]
                log.error(e.getMessage());
            }
        }

        return spu.getId().toString();
    }

    @Override
    public IPage<SpuInfo> list(SpuVo vo) {
        IPage<SpuInfo> page = new Page<>(vo.validPageNum(), vo.validPageSize());
        LambdaQueryWrapper<SpuInfo> qw = Wrappers.<SpuInfo>lambdaQuery().eq(vo.getCatalogId() != null, SpuInfo::getCatalogId, vo.getCatalogId())
                .eq(vo.getBrandId() != null, SpuInfo::getBrandId, vo.getBrandId())
                .eq(vo.getPublishStatus() != null, SpuInfo::getPublishStatus, vo.getPublishStatus())
                // 关键字
                .and(hasText(vo.getKey()), (wrapper) -> {
                    wrapper.eq(SpuInfo::getId, vo.getKey())
                            .or().like(SpuInfo::getSpuName, vo.getKey());
                });

        super.page(page, qw);

        for (SpuInfo record : page.getRecords()) {
            Optional<Category> cate = categoryService.getCacheById(record.getCatalogId());
            cate.ifPresent(cat -> record.setCatalogName(cat.getName()));

            if (record.getBrandId() != null) {
                Brand brand = brandService.getById(record.getBrandId());
                if (brand != null) {
                    record.setBrandName(brand.getName());
                }
            }
        }
        return page;
    }

    /**
     * 修改 spu 的规格参数
     *
     * @param spuId
     * @param specVoList
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateSpec(Long spuId, List<SpecVo> specVoList) {
        productAttrValueService.remove(Wrappers.<ProductAttrValue>lambdaQuery().eq(ProductAttrValue::getSpuId, spuId));
        productAttrValueService.saveSpecs(spuId, specVoList);
    }

    /**
     * 上架
     *
     * @param spuId
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void spuUp(Long spuId) {
        // 查询 sku 信息
        List<SkuInfo> skuInfos = skuInfoService.list(Wrappers.<SkuInfo>lambdaQuery().eq(SkuInfo::getSpuId, spuId));

        if (skuInfos.isEmpty()) {
            return;
        }

        // 调用库存系统，查看是否有库存
        Map<Long, Boolean> hasStockMap = new HashMap<>();
        List<Long> skuIds = skuInfos.stream().map(SkuInfo::getSkuId).collect(Collectors.toList());
        try {
            R<List<SkusHasStockTo>> r = wareClient.getSkusHasStock(skuIds);
            if (r.isOk()) {
                List<SkusHasStockTo> hasStockTos = r.getData();
                hasStockMap.putAll(hasStockTos.stream().collect(Collectors.toMap(SkusHasStockTo::getSkuId, SkusHasStockTo::isHasStock)));
            } else {
                log.error("库存服务调用失败，{}", r.getMsg());
            }
        } catch (Exception e) {
            // 连接超时
            // feign.RetryableException: Connect to localhost:11000 [/localhost] failed: connect timed out executing POST http://gulimall-ware/ware/getSkusHasStock
            log.error(e.getMessage());
        }

        List<SkuEsModel> skuEsModelList = skuInfos.stream().map(sku -> {
            SkuEsModel skuEsModel = new SkuEsModel();
            BeanUtils.copyProperties(sku, skuEsModel);
            skuEsModel.setSkuPrice(sku.getPrice());
            skuEsModel.setSkuImg(sku.getSkuDefaultImg());
            skuEsModel.setHotScore(0L);
            if (hasStockMap.isEmpty()) {
                // 设置默认值
                skuEsModel.setHasStock(true);
            } else {
                skuEsModel.setHasStock(hasStockMap.get(sku.getSkuId()));
            }

            // 查询品牌name和分类name
            if (sku.getBrandId() != null) {
                Brand brand = brandService.getById(sku.getBrandId());
                if (brand != null) {
                    skuEsModel.setBrandName(brand.getName());
                    skuEsModel.setBrandImg(brand.getLogo());
                }
            }

            String catalogName = categoryService.getCacheNameById(sku.getCatalogId());
            skuEsModel.setCatalogName(catalogName);

            return skuEsModel;
        }).collect(Collectors.toList());


        // 查询 sku 可以被用来检索的规格属性 searchType=1
        List<ProductAttrValue> attrValueList = productAttrValueService.list(Wrappers.<ProductAttrValue>lambdaUpdate().eq(ProductAttrValue::getSpuId, spuId));
        if (!attrValueList.isEmpty()) {

            // 过滤 + 类型转换
            List<SkuEsModel.Attrs> esAttrs = attrValueList.stream().filter(attrValue -> {
                Attr attr = attrService.getById(attrValue.getAttrId());
                return attr != null && attr.getSearchType() == 1;
            }).map(pav -> {
                SkuEsModel.Attrs attrs = new SkuEsModel.Attrs();
                BeanUtils.copyProperties(pav, attrs);
                return attrs;
            }).collect(Collectors.toList());

            if (!esAttrs.isEmpty()) {
                skuEsModelList.forEach(sem -> {
                    sem.setAttrs(esAttrs);
                });
            }
        }

        // 远程调用 es 服务
        try {
            R<Boolean> r = searchClient.productStatusUp(skuEsModelList);
            Boolean data = r.getData();
            if (Boolean.TRUE.equals(data)) {
                // 更改 spu 数据库状态
                super.update(Wrappers.<SpuInfo>lambdaUpdate().set(SpuInfo::getPublishStatus, SpuStatus.UP.ordinal()).set(SpuInfo::getUpdateTime, LocalDateTime.now()).eq(SpuInfo::getId, spuId));
            } else {
                // 保存失败
                throw new ServiceException("商品上架失败");
            }
        } catch (Exception e) {
            log.error(e.getMessage());
            if (e instanceof ServiceException) {
                throw e;
            }
            throw new ServiceException("商品上架失败，es连接异常");
        }
    }
}
